#include "t_box_input_http.h"
#include "nbr.h"

T_Box_Input_Http::T_Box_Input_Http(QNetworkReply *a_reply)
    : m_mutex(QMutex::Recursive)
    , m_reply(a_reply)
    , m_waiter(a_reply, true)
    , m_buffer(new quint8[c_buffer_size])
{
    m_file.setBuffer(&m_file_bytes);
    m_file.open(QIODevice::ReadOnly);
    //NetworkWaiter v_waiter(m_reply);
    m_waiter.waitBreakSize(c_pd_check_size);
    if(m_waiter.bytesAvailable()==0)
    {
        qDebug() << "(m_waiter.bytesAvailable()==0)";
    }
    Q_ASSERT(m_waiter.bytesAvailable()>=c_pd_check_size);
    m_first_read = m_waiter.readAll();
    m_file_bytes.append(m_first_read);
    m_temp_flv.setFileName("C:/temp.flv");
    m_temp_flv.open(QIODevice::ReadOnly);
}

T_Box_Input_Http::~T_Box_Input_Http()
{
    delete m_reply;
    delete [] m_buffer;
}

bool T_Box_Input_Http::isValid()
{
    QMutexLocker v_lock(&m_mutex);
    Q_UNUSED(v_lock);
    ////if(!m_file.isOpen()) return false;
    //FIXME
    return true;
}

AVInputFormat *T_Box_Input_Http::getAVInputFormat()
{
    QMutexLocker v_lock(&m_mutex);
    Q_UNUSED(v_lock);
    qDebug() << "T_Box_Input_Http::getAVInputFormat()";
    //const int c_pd_check_size = 4096;
    quint64 v_pos = m_file.pos();
    m_file.seek(0);
    qDebug() << "T_Box_Input_Http::getAVInputFormat(): v_pos=" << v_pos;
    m_pd_bytes = m_file.read(c_pd_check_size);
    Q_ASSERT(m_first_read.size()>=c_pd_check_size);
    Q_ASSERT(m_pd_bytes.size()>=c_pd_check_size);
    Q_ASSERT(m_first_read.left(1024)==m_pd_bytes.left(1024));
    AVProbeData v_probe_data;
    v_probe_data.filename = "";
    v_probe_data.buf_size = m_pd_bytes.size();
    v_probe_data.buf = (unsigned char *)m_pd_bytes.data();
    m_file.seek(v_pos);
    AVInputFormat *v_fmt = av_probe_input_format(&v_probe_data, 1);
    if(v_fmt)
    {
        qDebug() << v_fmt->long_name;
        qDebug() << v_fmt->name;
    }
    return v_fmt;
}

ByteIOContext *T_Box_Input_Http::getByteIOContext()
{
    QMutexLocker v_lock(&m_mutex);
    Q_UNUSED(v_lock);
    if(!m_file.isOpen()) return 0;
    int ret = init_put_byte(
            &m_bioc, //ByteIOContext *s
            m_buffer, //unsigned char *buffer,
            c_buffer_size,  //int buffer_size,
            0, //int write_flag,
            this, //void *opaque,
            T_Box_Input_Http::callback_read_packet, //int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
            NULL, //int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
            T_Box_Input_Http::callback_seek //int64_t (*seek)(void *opaque, int64_t offset, int whence)
            );
    qDebug() << "ret=" << ret;
    return &m_bioc;
}

AVFormatContext	*T_Box_Input_Http::getAVFormatContext()
{
    QMutexLocker v_lock(&m_mutex);
    Q_UNUSED(v_lock);
    if(!this->isValid())
    {
        qDebug() << "(!this->isValid())";
        return NULL;
    }
    AVInputFormat *v_fmt = this->getAVInputFormat();
    if(!v_fmt)
    {
        qDebug() << "(!v_fmt)";
        return NULL;
    }
    AVFormatContext	*v_format_ctx;
    if(::av_open_input_stream(
            &v_format_ctx,
            this->getByteIOContext(),
            "",
            v_fmt,
            NULL))
    {
        return NULL;
    }
    if(::av_find_stream_info(v_format_ctx)<0)
    {
        qDebug() << "Can't find stream info";
        av_close_input_file(v_format_ctx);
        return NULL;
    }
    return v_format_ctx;
}

T_Box_Player_Context *T_Box_Input_Http::getAVFormatContext2()
{
    QMutexLocker v_lock(&m_mutex);
    Q_UNUSED(v_lock);
    AVFormatContext	*v_format_ctx = this->getAVFormatContext();
    if(!v_format_ctx) return NULL;
    return new T_Box_Player_Context(v_format_ctx);
}

int T_Box_Input_Http::read_packet(uint8_t *buf, int buf_size)
{
    QMutexLocker v_lock(&m_mutex);
    Q_UNUSED(v_lock);
    qDebug() << "[T_Box_Input_Http::read_packet()]" << m_file.pos() << buf_size;
    Q_ASSERT(m_file.isOpen());
    m_file_bytes.append(m_waiter.readAll());
    if(m_file.bytesAvailable() < buf_size)
    {
        //NetworkWaiter v_waiter(m_reply);
        m_waiter.waitBreakSize(buf_size-m_file.bytesAvailable());
        m_file_bytes.append(m_waiter.readAll());
    }
    return m_file.read((char *)buf, buf_size);
}

int64_t T_Box_Input_Http::seek(int64_t offset, int whence)
{
    QMutexLocker v_lock(&m_mutex);
    Q_UNUSED(v_lock);
    if(!m_file.isOpen()) return -1;
    QString v_whence_name = p_seek_whence_name(whence);
    if(whence == SEEK_CUR)
    {
        //qDebug() << "[seek()]" <<v_whence_name << offset << m_file.pos();
    }
    else
    {
        //qDebug() << "[seek()]" <<v_whence_name << offset;
    }
    switch(whence)
    {
    case SEEK_SET:
        break;
    case SEEK_CUR:
        offset += m_file.pos();
        break;
    case SEEK_END:
        offset += m_file.size();
        break;
    case AVSEEK_SIZE:
        // return the filesize without seeking anywhere
        {
            QVariant v_cont_len = m_reply->header(QNetworkRequest::ContentLengthHeader);
            if(!v_cont_len.isValid()) return -1;
            quint64 v_cont_len_i64 = v_cont_len.toLongLong();
            qDebug() << "[v_cont_len_i64]" << v_cont_len_i64;
            return v_cont_len_i64;
        }
    default:
        return -1;
    }
    m_file_bytes.append(m_waiter.readAll());
    quint64 v_diff = offset - m_file.pos();
    qDebug() << "[v_diff]" << v_diff;
    quint64 v_avail = m_file.bytesAvailable();
    qDebug() << "[v_avail]" << v_avail;
    if(v_diff > 0 && v_avail < v_diff)
    {
        qDebug() << "[wait(1)]";
        qDebug() << "[wait(2)]";
        int v_wait = (v_diff-v_avail);
        qDebug() << "[v_wait]" << v_wait;
        //NetworkWaiter v_waiter(m_reply);
        m_waiter.waitBreakSize(v_wait);
        qDebug() << "[wait(3)]";
        m_file_bytes.append(m_waiter.readAll());
        qDebug() << "[wait(4)]";
    }
    qDebug() << "[seek(1)]";
    if(!m_file.seek(offset))
    {
        qDebug() << "[seek(2)]";
        qDebug() << "(!m_file.seek(offset))";
        return -1;
    }
    else
    {
        qDebug() << "[seek(3)]";
        return m_file.pos();
    }
    qDebug() << "[seek(4)]";
}

